package com.taomus.mytools.helper;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;

import com.taomus.mytools.helper.annotations.Column;
import com.taomus.mytools.helper.annotations.Wrapper;


public class MappingHelper {
	
	public static Object mapping(HttpServletRequest request,Class<?> dest) throws InstantiationException, IllegalAccessException{
		Object obj = dest.newInstance();
		Map<String,String[]> reqValue = request.getParameterMap();
		request2f(dest, obj, reqValue);
		return obj;
	}
	
	public static <T> Object mapping(Object src,Class<T> dest) throws InstantiationException, IllegalAccessException{
		if(src instanceof  Collection){
			return mappingList(src, dest);
		}else if(src instanceof Map){
			return mappingMap(src,dest);
		}else{
			//bean to bean
			return o2o(dest,src);
		}
	}
	@SuppressWarnings("unchecked")
	private static <T> Object mappingMap(Object src, Class<T> dest) throws InstantiationException, IllegalAccessException{
		Map<Object,?> srcMap = (Map<Object, ?>)src;
		Map<Object,Object> destMap = new HashMap<>();
		for(Object key : srcMap.keySet()){
			Object s = srcMap.get(key);
			if(s instanceof Collection){
				Collection<T> tlist = (Collection<T>) mappingList(s,dest);
				destMap.put(key, tlist);
			}else if(s instanceof Map){ 
				Map<Object,Object> dest2 = (Map<Object, Object>) mappingMap(s,dest);
				destMap.put(key, dest2);
			}else{
				Object dest2 = o2o(dest,s);
				destMap.put(key, dest2);
			}
		}
		return destMap;
	}
	
	private static <T> Object mappingList(Object src, Class<T> dest)
			throws InstantiationException, IllegalAccessException {
		Collection<T> destList = null;
		if(src instanceof Collection){
			destList = new LinkedList<>();
		}
		Collection<?> srclist = (Collection<?>) src;
		if(ObjectHelper.isNotNull(src)){
			for(Object srcObj : srclist){
				T instance = o2o(dest, srcObj);
				destList.add(instance);
			}
		}
		return destList;
	}
	
	private static <T> T o2o(Class<T> dest, Object srcObj)
			throws InstantiationException, IllegalAccessException{
		T instance = dest.newInstance();
		Class<?> srcClass = srcObj.getClass();
		Class<?> superClass = dest.getSuperclass();
		if(!superClass.equals(Object.class)){
			f2f(superClass, srcObj, instance, srcClass);
		}
		f2f(dest, srcObj, instance, srcClass);
		return instance;
	}
	
	private static <T> void request2f(Class<T> dest,Object obj,Map<String,String[]> value){
		for(Field field : dest.getDeclaredFields()){
			field.setAccessible(true);
			Column column=field.getAnnotation(Column.class);
			if(ObjectHelper.isNotNull(column)){
				if(value.containsKey(column.value())){
					try {
						field.set(obj,value.get(column.value()));
					} catch (IllegalArgumentException | IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}else{
				try {
					field.set(obj,field.getName().toLowerCase());
				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}
	private static <T> void f2f(Class<?> dest, Object srcObj, T instance, Class<?> srcClass)
			throws IllegalAccessException, InstantiationException{
		for(Field field : dest.getDeclaredFields()){
			field.setAccessible(true);
			Field srcField;
			try {
				srcField = srcClass.getDeclaredField(field.getName());
				srcField.setAccessible(true);
				Object val = srcField.get(srcObj);
				Wrapper wrapper = field.getAnnotation(Wrapper.class);
				if(ObjectHelper.isNotNull(wrapper) && ObjectHelper.isNotNull(wrapper.value())){
					Object wrapperObj = wrapper.value().newInstance();
					try {
						val = wrapper.value().getMethod(wrapper.method(),Object.class).invoke(wrapperObj,val);
					} catch (IllegalArgumentException
							| InvocationTargetException | NoSuchMethodException e) {
						e.printStackTrace();
					}
				}
				field.set(instance, val);
			} catch (NoSuchFieldException | SecurityException e) {
			}
		}
	}
}
